###########################################################################
#
#   Copyright 2010 American Public Media Group
#
#   This file is part of AIR2.
#
#   AIR2 is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   AIR2 is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
#
###########################################################################

package AIR2::SrcResponseSet;
use strict;
use base qw(AIR2::DB);
use Carp;
use Data::Dump qw( dump );
use Scalar::Util qw( blessed );

__PACKAGE__->meta->setup(
    table => 'src_response_set',

    columns => [
        srs_id     => { type => 'serial',  not_null => 1 },
        srs_src_id => { type => 'integer', not_null => 1 },
        srs_inq_id => { type => 'integer', not_null => 1 },
        srs_date   => {
            type     => 'datetime',
            not_null => 1
        },
        srs_uri  => { type => 'varchar', length => 255 },
        srs_type => {
            type     => 'character',
            default  => 'I',
            length   => 1,
            not_null => 1
        },
        srs_public_flag => { type => 'integer', default => 0, not_null => 1 },
        srs_delete_flag => { type => 'integer', default => 0, not_null => 1 },
        srs_translated_flag =>
            { type => 'integer', default => 0, not_null => 1 },
        srs_export_flag => { type => 'integer', default => 0, not_null => 1 },
        srs_loc_id      => {
            type     => 'integer',
            default  => 52,          # en_US
            not_null => 1,
        },
        srs_conf_level => { type => 'character', length   => 1 },
        srs_cre_user   => { type => 'integer',   not_null => 1 },
        srs_upd_user   => { type => 'integer' },
        srs_cre_dtim   => {
            type     => 'datetime',
            not_null => 1
        },
        srs_upd_dtim => { type => 'datetime' },
    ],

    primary_key_columns => ['srs_id'],

    foreign_keys => [
        cre_user => {
            class       => 'AIR2::User',
            key_columns => { srs_cre_user => 'user_id' },
        },

        inquiry => {
            class       => 'AIR2::Inquiry',
            key_columns => { srs_inq_id => 'inq_id' },
        },

        source => {
            class       => 'AIR2::Source',
            key_columns => { srs_src_id => 'src_id' },
        },

        upd_user => {
            class       => 'AIR2::User',
            key_columns => { srs_upd_user => 'user_id' },
        },

        locale => {
            class       => 'AIR2::Locale',
            key_columns => { srs_loc_id => 'loc_id' },
        },
    ],

    relationships => [
        responses => {
            class      => 'AIR2::SrcResponse',
            column_map => { srs_id => 'sr_srs_id' },
            type       => 'one to many',
        },

        annotations => {
            class      => 'AIR2::SrsAnnotation',
            column_map => { srs_id => 'srsan_srs_id' },
            type       => 'one to many',
        },
    ],
);

my @indexables = qw(
    responses
    annotations
);

sub load_indexable_rels {
    my $self = shift;
    for my $rel (@indexables) {
        $self->$rel;
    }
}

sub init_indexer {
    my $self = shift;
    return $self->SUPER::init_indexer(
        prune => {

        },
        max_depth        => 1,
        xml_root_element => 'responseset',
        force_load       => 0,
        @_
    );
}

=head2 get_authz( I<project_authz>, I<src_authz> )

Returns array of org_ids representing the intersection
of the Project- and Source-related authz values.

=cut

sub get_authz {
    my $self          = shift;
    my $project_authz = shift or croak "project_authz required";
    my $src_authz     = shift or croak "src_authz required";

    # get intersection
    my @authz;
    my %p = map { $_ => $_ } @$project_authz;
    for my $oid (@$src_authz) {
        if ( exists $p{$oid} ) {
            push @authz, $oid;
        }
    }
    return \@authz;
}

=head2 as_xml( I<args> )

Returns SrcResponseSet as XML string, suitable for indexing.

I<args> should contain a Rose::DBx::Object::Indexed::Indexer
object and other objects relevant to the XML structure.
See bin/resp2xml.pl for example usage.

=cut

sub as_xml {
    my $set     = shift;
    my $args    = shift or croak "args required";
    my $debug   = delete $args->{debug} || 0;
    my $indexer = delete $args->{indexer}
        || $set->init_indexer( debug => $debug, );
    my $base_dir = delete $args->{base_dir}
        || Path::Class::dir('no/such/dir');
    my $source = delete $args->{source}
        || AIR2::SearchUtils::get_source_with_authz( $set->srs_src_id );
    my $organizations = delete $args->{organizations}
        || AIR2::SearchUtils::all_organizations_by_id();

    my $pk = $set->srs_id;
    $set->load_indexable_rels;
    my $dmp = $indexer->serialize_object($set);

    $debug and dump $dmp;

    my $inquiry;

    for my $response ( @{ $dmp->{responses} } ) {

        my $date = $response->{sr_upd_dtim};

        #$date =~ s/^(\d+-\d+-\d+) .+/$1/;

        my $question
            = AIR2::SearchUtils::get_question( $response->{sr_ques_id} );

        # flatten the related orgs, inquiry,
        # question and answer into a single virtual field
        # so we can find it as a set.
        $response->{qa} = join(
            ':',
            join(
                ',',
                @{  $question->inquiry->project_inquiries->[0]
                        ->project->get_authz()
                    }
            ),
            $question->inquiry->inq_uuid,
            $question->ques_dis_seq,
            $date,

            # delete the response from the object
            # because we want to protect it with the authz in this
            # virtual field.
            delete $response->{sr_orig_value}
        );
        $response->{ques_uuid}  = $question->ques_uuid;
        $response->{ques_value} = $question->ques_value;

        # the inquiry parent is shared. we load it from the question, once.
        $inquiry ||= $question->inquiry;
    }

    if ( !$inquiry ) {
        croak "no parent inquiry for response set $pk";
    }
    $dmp->{inq_uuid}      = $inquiry->inq_uuid;
    $dmp->{inq_title}     = $inquiry->inq_title;
    $dmp->{inq_ext_title} = $inquiry->inq_ext_title;
    $dmp->{src_uuid}      = $source->{uuid};
    $dmp->{src_name}      = $source->{name};
    $dmp->{src_username}  = $source->{username};

    # a single parent inquiry could have multiple parent projects.
    # a single project could have multiple parent organizations.
    # this response_set set inherits all the authz for all projects.
    # TODO authz tests around the possible combinations.
    my @projects;
    my @organizations;
    my @authz;
    for my $pinq ( @{ $inquiry->project_inquiries } ) {
        my $project = $pinq->get_project();
        push @projects,
            {
            prj_uuid         => $project->prj_uuid,
            prj_name         => $project->prj_name,
            prj_display_name => $project->prj_display_name,
            prj_shared_flag  => $project->prj_shared_flag,
            };
        push @organizations,
            {
            org_names => $project->get_org_names(),
            org_uuids => $project->get_org_uuids(),
            org_ids   => $project->get_org_ids(),
            };
        push @authz,
            @{ $set->get_authz( $project->get_authz(), $source->{authz} ) };
    }
    $dmp->{projects}      = \@projects;
    $dmp->{organizations} = \@organizations;

    # composite virtual fields
    $dmp->{inq_uuid_title}
        = join( ':', $dmp->{inq_uuid}, $inquiry->get_title );
    $dmp->{prj_uuid_titles}
        = [ map { join( ':', $_->{prj_uuid}, $_->{prj_display_name} ) }
            @projects ];

    # facet building
    $dmp->{srs_ts}
        = AIR2::SearchUtils::dtim_string_to_ymd( $dmp->{srs_date} );

    my $xml = $indexer->to_xml( $dmp, $set );

    # hack in the authz string
    my $authz_str = join( ",", @authz );
    my $root = $indexer->xml_root_element;
    $xml =~ s,^<$root,<$root authz="$authz_str",;

    return $xml;
}

1;
